package com.redepronik.negosys.rrhh.service;

import static com.redepronik.negosys.utils.Utils.presentaMensaje;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.faces.application.FacesMessage;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.redepronik.negosys.invfac.entityAux.PersonaCedulaNombre;
import com.redepronik.negosys.rrhh.dao.EmpleadoCargoDao;
import com.redepronik.negosys.rrhh.dao.EmpleadoDao;
import com.redepronik.negosys.rrhh.dao.PersonaDao;
import com.redepronik.negosys.rrhh.entity.Empleado;
import com.redepronik.negosys.rrhh.entity.Empleadocargo;
import com.redepronik.negosys.rrhh.entity.Persona;
import com.redepronik.negosys.seguridad.entity.Rol;
import com.redepronik.negosys.seguridad.entity.Rolusuario;
import com.redepronik.negosys.seguridad.entity.Usuario;
import com.redepronik.negosys.seguridad.service.RolService;
import com.redepronik.negosys.seguridad.service.UsuarioService;

@Service
public class EmpleadoServiceImpl implements EmpleadoService, Serializable {

	private static final long serialVersionUID = 1L;

	@Autowired
	private PersonaService personaService;

	@Autowired
	private PersonaDao personaDao;

	@Autowired
	private UsuarioService usuarioService;

	@Autowired
	private CargoService cargoService;

	@Autowired
	private RolService rolService;

	@Autowired
	private EmpleadoDao empleadoDao;

	@Autowired
	private EmpleadoCargoDao empleadoCargoDao;

	private Usuario usuario;

	private ValidatorFactory factory = Validation
			.buildDefaultValidatorFactory();
	private Validator validator = factory.getValidator();

	public void actualizar(Persona persona) {
		Set<ConstraintViolation<Empleado>> violationsPersona = validator
				.validate(persona.getEmpleado());

		if (violationsPersona.size() > 0)
			for (ConstraintViolation<Empleado> cv : violationsPersona)
				presentaMensaje(FacesMessage.SEVERITY_INFO, cv.getMessage());
		else if (personaService.actualizar(persona))
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"EMPLEADO ACTUALIZADO DE MANERA CORRECTA", "cerrar", true);
		else
			presentaMensaje(FacesMessage.SEVERITY_INFO, "EXISTE UN ERROR");
	}

	public Map<String, Object> autorizacion(String login, String pass) {
		Map<String, Object> parametro = new HashMap<String, Object>();

		Usuario usuario = usuarioService.obtenerPorLoginSimple(login);
		boolean bn = false;
		if (usuario == null)
			parametro.put("mensaje", new FacesMessage(
					FacesMessage.SEVERITY_ERROR, "ERROR",
					"EL USUARIO NO EXISTE"));
		else {
			if (usuarioService.generarClave(pass).compareTo(
					usuario.getPassword()) == 0) {
				for (Rolusuario rolUsuario : usuario.getRolusuarios())
					if (rolUsuario.getRol().getNombre().compareTo("ADMI") == 0) {
						bn = true;
						parametro.put("correcto", bn);
						parametro.put("mensaje", new FacesMessage(
								FacesMessage.SEVERITY_INFO, "CORRECTO",
								"CORRECTO"));
					}
				if (!bn)
					parametro.put("mensaje", new FacesMessage(
							FacesMessage.SEVERITY_ERROR, "ERROR",
							"EL USUARIO NO ES ADMINISTRADOR"));
			} else
				parametro.put("mensaje", new FacesMessage(
						FacesMessage.SEVERITY_ERROR, "ERROR",
						"LA CLAVE NO ES VALIDA"));
		}
		if (!bn)
			parametro.put("correcto", false);

		return parametro;
	}

	public Long contar() {
		return (Long) empleadoDao.contar(Empleado.class, "empleadoid");
	}

	public void eliminar(Persona persona) {
		persona.getEmpleado().setActivo(
				persona.getEmpleado().getActivo() ? false : true);
		personaDao.actualizar(persona);

		if (persona.getEmpleado().getActivo())
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"SE ACTIVÓ EL EMPLEADO: " + persona.getApellido() + " "
							+ persona.getNombre());
		else
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"SE DESACTIVÓ EL EMPLEADO: " + persona.getApellido() + " "
							+ persona.getNombre());
	}

	public void insertar(Persona persona) {
		persona.getEmpleado().setActivo(true);
		persona.getEmpleado().setFolio(String.valueOf(contar() + 1));
		persona.getEmpleado().setPersona(persona);

		Set<ConstraintViolation<Empleado>> violationsEmpleado = validator
				.validate(persona.getEmpleado());

		if (violationsEmpleado.size() > 0)
			for (ConstraintViolation<Empleado> cv : violationsEmpleado)
				presentaMensaje(FacesMessage.SEVERITY_INFO, cv.getMessage());

		else {
			boolean retorno = false;

			if (persona.getPersonaid() == null)
				retorno = personaService.insertar(persona);
			else
				retorno = personaService.actualizar(persona);

			if (retorno)
				presentaMensaje(FacesMessage.SEVERITY_INFO,
						"EMPLEADO INSERTADO DE MANERA CORRECTA", "cerrar", true);
			else
				presentaMensaje(FacesMessage.SEVERITY_INFO, "EXISTE UN ERROR");
		}
	}

	public String insertarCargos(Persona persona) {
		actualizar(persona);

		usuario = usuarioService.obtenerPorLoginSimple(persona.getCedula());
		if (usuario.getRolusuarios() == null)
			usuario.setRolusuarios(new ArrayList<Rolusuario>());
		for (Empleadocargo ec : persona.getEmpleado().getEmpleadocargos()) {
			Rol rol = null;
			if (ec.getCargo().getNombre().compareTo("ADMINISTRADOR") == 0)
				rol = rolService.obtenerPorNombre("ADMI");
			else if (ec.getCargo().getNombre().compareTo("SUPERVISOR/CAJA") == 0)
				rol = rolService.obtenerPorNombre("SUCA");
			else if (ec.getCargo().getNombre().compareTo("BODEGUERO") == 0)
				rol = rolService.obtenerPorNombre("BODE");
			else if (ec.getCargo().getNombre().compareTo("CAJERO") == 0)
				rol = rolService.obtenerPorNombre("CAJA");
			else if (ec.getCargo().getNombre().compareTo("VENDEDOR") == 0)
				rol = rolService.obtenerPorNombre("VEND");
			else if (ec.getCargo().getNombre().compareTo("CHOFER") == 0)
				rol = rolService.obtenerPorNombre("CHOF");
			else if (ec.getCargo().getNombre()
					.compareTo("ADMINISTRADOR/SEGURIDAD") == 0)
				rol = rolService.obtenerPorNombre("SEGU");
			else if (ec.getCargo().getNombre().compareTo("REPORTEADOR") == 0)
				rol = rolService.obtenerPorNombre("REPO");

			Boolean bn = false;

			for (Rolusuario ru : usuario.getRolusuarios()) {
				if (rol.getRolid() == ru.getRol().getRolid()) {
					bn = true;
				}
			}

			if (!bn) {
				Rolusuario rolUsuario = new Rolusuario();
				rolUsuario.setRol(rol);
				rolUsuario.setActivo(true);
				usuario.addRolusuario(rolUsuario);
			}
		}
		usuarioService.actualizar(usuario);
		return "SAVE";
	}

	public List<Empleadocargo> cargarCargos(
			List<Empleadocargo> listaEmpleadoCargos, Persona persona) {
		listaEmpleadoCargos = persona.getEmpleado().getEmpleadocargos();
		return listaEmpleadoCargos;
	}

	public List<Persona> obtener() {
		List<Persona> lista = personaDao
				.obtenerPorHql(
						"select p from Persona p "
								+ "left join fetch p.emailpersonas "
								+ "left join fetch p.telefonopersonas "
								+ "left join fetch p.empleadocargos "
								+ "inner join p.empleado e order by p.apellido, p.nombre",
						new Object[] {});
		return lista;
	}

	public List<Persona> obtener(String nombreEmpleado) {
		List<Persona> lista = personaDao
				.obtenerPorHql(
						"select p from Persona p inner join p.empleado c where (p.cedula like ?1 or p.nombre like ?1 or p.apellido like ?1) and p.activo=true and c.activo=true",
						new Object[] { "%" + nombreEmpleado + "%" });
		return lista;
	}

	public List<Persona> obtenerActivos() {
		List<Persona> lista = personaDao
				.obtenerPorHql(
						"select p from Persona p inner join p.empleado e where p.activo=true order by p.apellido, p.nombre",
						new Object[] {});
		return lista;
	}

	public Empleadocargo obtenerEmpleadoCargoPorCedulaAndCargo(String cedula,
			Integer cargoId) {
		return empleadoCargoDao
				.obtenerPorHql(
						"select ec from Empleadocargo ec inner join ec.empleado e "
								+ "inner join e.persona p "
								+ "inner join ec.cargo c "
								+ "where p.activo=true and p.cedula=?1 and c.cargoid=?2 and ec.actual=true",
						new Object[] { cedula, cargoId }).get(0);
	}

	@SuppressWarnings("unchecked")
	public List<PersonaCedulaNombre> obtenerPorCargo(int cargo) {
		return (List<PersonaCedulaNombre>) personaDao
				.obtenerPorSql1(
						"select ec.empleadocargoid as id, p.cedula as cedula, p.nombre as nombre, p.apellido as apellido from rrhh.persona p "
								+ "inner join rrhh.empleado e on (e.personaid=p.personaid) "
								+ "inner join rrhh.empleadocargo ec on (ec.empleadoid=e.empleadoid) "
								+ "inner join rrhh.cargo c on (c.cargoid=ec.cargoid) "
								+ "where p.activo=true and e.activo=true and ec.actual=true and c.activo=true and c.cargoid="
								+ cargo + " order by p.apellido, p.nombre",
						PersonaCedulaNombre.class);
	}

	public Persona obtenerPorCedula(String cedula) {
		Persona p = personaService.obtenerPorCedula(cedula);
		return p;
	}

	public Empleadocargo obtenerPorEmpleadoCargoId(int empladoCargoId) {
		return empleadoCargoDao.obtenerPorId(Empleadocargo.class,
				empladoCargoId);
	}

	public List<Persona> obtenerTodosPorBusqueda(int criterioBusquedaCargo,
			String criterioBusquedaEmpleado, int criterioBusquedaCiudad) {
		List<Persona> lista = null;

		if (criterioBusquedaEmpleado.compareToIgnoreCase("") == 0
				&& criterioBusquedaCiudad == 0 && criterioBusquedaCargo == 0)
			presentaMensaje(FacesMessage.SEVERITY_ERROR,
					"INGRESE UN CRITERIO DE BUSQUEDA");
		else {
			if (criterioBusquedaCargo != 0
					|| criterioBusquedaEmpleado.length() >= 3
					|| criterioBusquedaCiudad != 0) {
				if (criterioBusquedaEmpleado.compareToIgnoreCase("") != 0
						&& criterioBusquedaCiudad != 0)
					lista = personaDao
							.obtenerPorHql(
									"select distinct p from Persona p "
											+ "inner join fetch p.empleado e "
											+ "left join fetch e.empleadocargos ec "
											+ "left join ec.cargo c"
											+ "left join fetch p.emailpersonas "
											+ "left join fetch p.telefonopersonas "
											+ "inner join p.ciudad cd "
											+ "where (cd.ciudadid=?2 "
											+ "and (p.cedula like ?1 or p.nombre like ?1 or p.apellido like ?1)) "
											+ "order by p.apellido, p.nombre",
									new Object[] {
											"%" + criterioBusquedaEmpleado
													+ "%",
											criterioBusquedaCiudad });
				else if (criterioBusquedaCargo != 0)
					lista = personaDao
							.obtenerPorHql(
									"select distinct p from Persona p "
											+ "inner join fetch p.empleado e "
											+ "left join fetch e.empleadocargos ec "
											+ "left join ec.cargo c "
											+ "left join fetch p.emailpersonas "
											+ "left join fetch p.telefonopersonas "
											+ "where c.cargoid=?1 order by p.apellido, p.nombre",
									new Object[] { criterioBusquedaCargo });
				else if (criterioBusquedaEmpleado.compareToIgnoreCase("") != 0)
					lista = personaDao
							.obtenerPorHql(
									"select distinct p from Persona p "
											+ "inner join fetch p.empleado e "
											+ "left join fetch e.empleadocargos ec "
											+ "left join ec.cargo "
											+ "left join fetch p.emailpersonas "
											+ "left join fetch p.telefonopersonas "
											+ "where (p.cedula like ?1 or p.nombre like ?1 or p.apellido like ?1) "
											+ "order by p.apellido, p.nombre",
									new Object[] { "%"
											+ criterioBusquedaEmpleado + "%" });
				else if (criterioBusquedaCiudad != 0)
					lista = personaDao.obtenerPorHql(
							"select distinct p from Persona p "
									+ "inner join fetch p.empleado e "
									+ "left join fetch e.empleadocargos ec "
									+ "left join ec.cargo "
									+ "left join fetch p.emailpersonas "
									+ "left join fetch p.telefonopersonas "
									+ "inner join p.ciudad cd "
									+ "where cd.ciudadid=?1 "
									+ "order by p.apellido, p.nombre",
							new Object[] { criterioBusquedaCiudad });
				if (lista.isEmpty())
					presentaMensaje(FacesMessage.SEVERITY_INFO,
							"NO SE ENCONTRO NINGUNA COINCIDENCIA");

			} else
				presentaMensaje(FacesMessage.SEVERITY_ERROR,
						"INGRESE MINIMO 3 CARACTERES");
		}
		return lista;
	}
}